﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Windows.Media;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Tetris
{
    class Logic
    {
        private List<Node> nodesOnFloor;
        private int score;
        private string savegame = @"C:\Tetris_score.txt";//путь, где будет храниться файл сохранения
        private GameField field;
        private readonly Painter paint;
        private readonly Handler kh;
        private Figure currentFigure;
        private Figure nextFigure;
        private  int speed = 500;
        //private SoundPlay player;//консольные бипы так и не проигрываются, никак не разберусь почему, 
        //пока оставил класс, как есть, в качестве примера
        private MusicPlayer m_player;
        private FileStream nodes;
        private BinaryFormatter form = new BinaryFormatter();


        public Logic(GameField gamefield, Painter painter, Handler handler, MusicPlayer sound)
        {
            field = gamefield;
            paint = painter;
            kh = handler;
            nodesOnFloor = new List<Node>();
            m_player = sound;
            kh.KeyLeft += Left;
            kh.KeyUp += Up;
            kh.KeyRight += Right;
            kh.KeyDown += Down;
            kh.Pause += Pause;
        }

        public void PlayGame()
        {
            m_player.PlayMusic();
            if (File.Exists(savegame))//проверка наличия сохранения, чтобы не предлагать загрузить несуществующее
                LoadGameScores();
            Console.Clear();
            paint.DrawGameFieldFrame(field);
            currentFigure = CreateFigure(10, 3);
            Thread.Sleep(150);//пауза, чтобы 1 следующая фигура была другой
            while (!CheckList.IsGameOver(nodesOnFloor))
            {
                nextFigure = CreateFigure(10, 3);

                for (;;)
                {
                    paint.ClearFigure(currentFigure);//очищаем фигуру перед ходом
                    kh.QueryKB();//события на клавиши
                    if (!CheckList.IsOnFloor(currentFigure, field) && !CheckList.IsOnOtherFigures(currentFigure, nodesOnFloor))
                    {
                        currentFigure.MoveDown();
                    }
                    paint.DrawFigure(currentFigure, field);
                    if (CheckList.IsOnFloor(currentFigure, field) || CheckList.IsOnOtherFigures(currentFigure, nodesOnFloor))
                    {
                        int countLines = 0;
                        //добавление нодов фигуры в список
                        nodesOnFloor.Add(currentFigure.Node1);
                        nodesOnFloor.Add(currentFigure.Node2);
                        nodesOnFloor.Add(currentFigure.Node3);
                        nodesOnFloor.Add(currentFigure.Node4);
                        //проверка заполненности рядов списка, удаление элементов заполненных рядов, сдвиг остальных вниз
                        countLines = CountFullRows();
                        score += CountScorePoints(countLines);//подсчет очков
                        currentFigure = nextFigure;//перенос "ожидающей" фигуры в текущую
                        Console.Clear();
                        paint.DrawGameFieldFrame(field);
                        break;
                    }
                    paint.DrawScoreAndNextFigure(field, 4, score, 1, nextFigure);
                    paint.DrawNodesOnFloor(nodesOnFloor);
                    Thread.Sleep(ChangeSpeed());//скорость падения фигур
                }

            }
            m_player.StopMusic();
            Console.SetCursorPosition(7, 12);
            Console.WriteLine("GAME OVER");
        }

        private Figure CreateFigure(int controlX, int controlY)
        {
            Figure tempFigure = new Figure();
            if (tempFigure.figureType == FigureType.Line)
                tempFigure.CreateLine(controlX, controlY);
            if (tempFigure.figureType == FigureType.Square)
                tempFigure.CreateSquare(controlX, controlY);
            if (tempFigure.figureType == FigureType.Piramyd)
                tempFigure.CreatePyramid(controlX, controlY);
            if (tempFigure.figureType == FigureType.LLeft)
                tempFigure.CreateLleft(controlX, controlY);
            if (tempFigure.figureType == FigureType.LRight)
                tempFigure.CreateLright(controlX, controlY);
            if (tempFigure.figureType == FigureType.ZLeft)
                tempFigure.CreateZleft(controlX, controlY);
            if (tempFigure.figureType == FigureType.ZRight)
                tempFigure.CreateZright(controlX, controlY);
            return tempFigure;
        }

        private int CountScorePoints(int fullLines)
        {
            if (fullLines == 1)
                return 100;
            if (fullLines == 2)
                return 300;
            if (fullLines == 3)
                return 700;
            if (fullLines == 4)
                return 1500;
            return 0;
        }

        private int ChangeSpeed()
        {
            if (score > 5000 && score < 9000)
                speed = 400;
            if (score > 9000 && score < 13000)
                speed = 300;
            if (score > 13000 && score < 17000)
                speed = 250;
            if (score > 17000 && score < 21000)
                speed = 200;
            if (score > 21000 && score < 25000)
                speed = 150;
            if (score > 25000)
                speed = 100;
            return speed;
        }

        private int CountFullRows()
        {
            int counter = 0;
            for (int i = field.StartY; i < field.StartY + field.height; i++)
            {
                if (CheckList.IsRowFull(nodesOnFloor, i))
                {
                    counter++;
                    nodesOnFloor.RemoveAll(node => node.Y == i);
                    foreach (var node in nodesOnFloor)
                    {
                        if (node.Y < i) node.MoveDown();
                    }
                }
            }
            return counter;
        }

        private void Left(object sender, EventArgs e)
        {
            currentFigure.MoveLeft();
            if (!CheckList.IsFigureOnField(currentFigure, field) ||
                CheckList.IsOnOtherFigures(currentFigure, nodesOnFloor))
                currentFigure.MoveRight();
        }

        private void Right(object sender, EventArgs e)
        {
            currentFigure.MoveRight();
            if (!CheckList.IsFigureOnField(currentFigure, field) ||
                CheckList.IsOnOtherFigures(currentFigure, nodesOnFloor))
                currentFigure.MoveLeft();
        }

        private void Up(object sender, EventArgs e)
        {
            currentFigure.Rotate();//решение не очень, но с тестовой фигурой и отдельным методом, как у Валеры, у меня что-то пока не срослось
            if (!CheckList.IsFigureOnField(currentFigure, field) ||
                CheckList.IsOnOtherFigures(currentFigure, nodesOnFloor))
            {
                currentFigure.Rotate();
                currentFigure.Rotate();
                currentFigure.Rotate();
            }
        }


        private void Down(object sender, EventArgs e)
        {
            if (!CheckList.IsOnOtherFigures(currentFigure, nodesOnFloor) && 
                !CheckList.IsOnFloor(currentFigure, field))
                currentFigure.MoveDown();
        }

        private void Pause(object sender, EventArgs e)
        {
            //ConsoleKeyInfo key;
            SaveGameScores();
            //do
            //{
            //    key = Console.ReadKey(true);
            //}
            //while (key.Key != ConsoleKey.Spacebar);
        }
        
        public void SaveGameScores()
        {
            Console.SetCursorPosition(6, 12);
            Console.WriteLine("Желаете сохранить набранные очки и выйти? Y/N");
            string choice = Console.ReadLine();
            if (choice.ToUpper() == "Y")
            {
                File.WriteAllText(savegame, score.ToString());
                nodes = new FileStream(@"C:\Tetris.dat", FileMode.OpenOrCreate);//сериализация списка нодов
                form.Serialize(nodes, nodesOnFloor);
                Environment.Exit(0);//выход из приложения
            }
            else
            {
                Console.Clear();
                paint.DrawGameFieldFrame(field);
                paint.DrawNodesOnFloor(nodesOnFloor);
                paint.DrawScoreAndNextFigure(field, 4, score, speed, nextFigure);
            }
        }

        public void LoadGameScores()
        {
            Console.SetCursorPosition(6, 12);
            Console.WriteLine("Желаете загрузить сохранение игры? Y/N");
            string choice = Console.ReadLine();
            switch (choice.ToUpper())
            {
                case "Y":
                    {
                        score = Int32.Parse(File.ReadAllText(savegame));// загрузка файла с очками
                        File.Delete(savegame);
                        nodes = new FileStream(@"C:\Tetris.dat", FileMode.OpenOrCreate);// загрузка файла со списком нодов
                        nodesOnFloor = (List<Node>)form.Deserialize(nodes);
                        nodes.Close();
                        File.Delete(@"C:\Tetris.dat");
                    }
                    break;
                case "N":
                    {
                        File.Delete(savegame);
                        File.Delete(@"C:\Tetris.dat");
                    }
                    break;
            } 
        }

    }
}

